/* PHPSerializer.java
 *
 * Author:       Ma Bingyao <andot@ujn.edu.cn>
 * Copyright:    CoolCode.CN
 * Version:      2.1
 * LastModified: 2006-08-09
 * This library is free.  You can redistribute it and/or modify it.
 * http://www.coolcode.cn/?p=202
 * modified by lk0183 for Generics and lk's DynamicForm 2012-6-12 
 */
package dkr.core.serialize;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;


class UnSerializeResult {
    public Object value;
    public int hv;
    public UnSerializeResult() {}

    public UnSerializeResult(Object value, int hv) {
        this.value = value;
        this.hv = hv;
    }
}


public class PHPSerializer {
    private static Package[] __packages = Package.getPackages();
    private static final byte __Quote = 34;
    private static final byte __0 = 48;
    private static final byte __1 = 49;
    private static final byte __Colon = 58;
    private static final byte __Semicolon = 59;
    private static final byte __C = 67;
    private static final byte __N = 78;
    private static final byte __O = 79;
    private static final byte __R = 82;
    private static final byte __U = 85;
    private static final byte __Slash = 92;
    private static final byte __a = 97;
    private static final byte __b = 98;
    private static final byte __d = 100;
    private static final byte __i = 105;
    private static final byte __r = 114;
    private static final byte __s = 115;
    private static final byte __LeftB = 123;
    private static final byte __RightB = 125;
    private static final String __NAN = new String("NAN");
    private static final String __INF = new String("INF");
    private static final String __NINF = new String("-INF");
    private static final byte __m = 109;	//序列化给js端时，map转为object
    private PHPSerializer() {}
    public static final int READER_JAVA = 0;
    public static final int READER_PHP = 1;
    public static final int READER_JS = 2;
    public static final int READER_FLASH = 3;
    
    public static final String PHPSerializableClassName = "__classname";

    public static byte[] serialize(Object obj) {
        return serialize(obj, "UTF-8", READER_PHP);
    }
    
    public static byte[] serialize2Js(Object obj){
    	return serialize(obj, "UTF-8", READER_JS);
    }
    
    public static byte[] serialize(Object obj, int reader){
    	return serialize(obj, "UTF-8", reader);
    }

    private static byte[] serialize(Object obj, String charset, int reader) {
        Map<Object, Object> ht = new HashMap<Object, Object>();
        int hv = 1;
        ByteArrayOutputStream stream = new ByteArrayOutputStream();

        hv = serialize(stream, obj, ht, hv, charset, reader);
        byte[] result = stream.toByteArray();

        try {
            stream.close();
        } catch (Exception e) {}
        return result;
    }

    @SuppressWarnings("unchecked")
	private static int serialize(ByteArrayOutputStream stream, Object obj, Map<Object, Object> ht, int hv, String charset, int reader) {
        if (obj == null) {
            hv++;
            writeNull(stream);
        } else {
            if (obj instanceof Boolean) {
                hv++;
                writeBoolean(stream, ((Boolean) obj).booleanValue() ? __1 : __0);
            } else if ((obj instanceof Byte) || (obj instanceof Short)
                    || (obj instanceof Integer)) {
                hv++;
                writeInteger(stream, getBytes(obj));
            } else if (obj instanceof Long) {
                hv++;
                writeDouble(stream, getBytes(obj));
            } else if(obj instanceof BigInteger || obj instanceof BigDecimal){
                hv++;
                writeDouble(stream, getBytes(obj));            	
            } else if (obj instanceof Float) {
                hv++;
                Float f = (Float) obj;

                if (f.isNaN()) {
                    writeDouble(stream, getBytes(__NAN));
                } else if (f.isInfinite()) {
                    if (f.floatValue() > 0) {
                        writeDouble(stream, getBytes(__INF));
                    } else {
                        writeDouble(stream, getBytes(__NINF));
                    }
                } else {
                    writeDouble(stream, getBytes(f));
                }
            } else if (obj instanceof Double) {
                hv++;
                Double d = (Double) obj;

                if (d.isNaN()) {
                    writeDouble(stream, getBytes(__NAN));
                } else if (d.isInfinite()) {
                    if (d.doubleValue() > 0) {
                        writeDouble(stream, getBytes(__INF));
                    } else {
                        writeDouble(stream, getBytes(__NINF));
                    }
                } else {
                    writeDouble(stream, getBytes(d));
                }
            } else if(obj instanceof Date){
            	Long time = ((Date)obj).getTime();
                hv++;
                writeDouble(stream, getBytes(time));
            } else if ((obj instanceof Character) || (obj instanceof String)) {
                hv++;
                int length = -1;
                if(READER_JS == reader || READER_FLASH == reader)
                	length = String.valueOf(obj).length();
                writeString(stream, getBytes(obj, charset), length);
            } else if (obj.getClass().isArray()) {
            	hv = writeArray(stream, obj, ht, hv, charset, reader);
            } else if (obj instanceof List) {
            	hv = writeList(stream, (List<Object>) obj, ht, hv, charset, reader);
            } 
            else if (obj instanceof Map) {
                hv = writeMap(stream, (Map<Object, Object>) obj, ht, hv, charset,reader);
            } 
            else if(obj instanceof Iterable){
                hv = writeIterator(stream, ((Iterable<Object>) obj).iterator(), ht, hv, charset, reader);
            }
            else if(obj instanceof Iterator){
                hv = writeIterator(stream, ((Iterator<Object>) obj), ht, hv, charset, reader);
            }
            else {
                hv = writeObject(stream, obj, ht, hv, charset, reader);
            }
        }
        return hv;
    }

    private static void writeNull(ByteArrayOutputStream stream) {
        stream.write(__N);
        stream.write(__Semicolon);
    }

//    private static void writeRef(ByteArrayOutputStream stream, byte[] r) {
//        stream.write(__r);
//        stream.write(__Colon);
//        stream.write(r, 0, r.length);
//        stream.write(__Semicolon);
//    }
//
//    private static void writePointRef(ByteArrayOutputStream stream, byte[] p) {
//        stream.write(__R);
//        stream.write(__Colon);
//        stream.write(p, 0, p.length);
//        stream.write(__Semicolon);
//    }

    private static void writeBoolean(ByteArrayOutputStream stream, byte b) {
        stream.write(__b);
        stream.write(__Colon);
        stream.write(b);
        stream.write(__Semicolon);
    }

    private static void writeInteger(ByteArrayOutputStream stream, byte[] i) {
        stream.write(__i);
        stream.write(__Colon);
        stream.write(i, 0, i.length);
        stream.write(__Semicolon);
    }

    private static void writeDouble(ByteArrayOutputStream stream, byte[] d) {
        stream.write(__d);
        stream.write(__Colon);
        stream.write(d, 0, d.length);
        stream.write(__Semicolon);
    }

    private static void writeString(ByteArrayOutputStream stream, byte[] s, int length) {
        byte[] slen = getBytes(new Integer((length >= 0) ? length : s.length));
        stream.write(__s);
        stream.write(__Colon);
        stream.write(slen, 0, slen.length);
        stream.write(__Colon);
        stream.write(__Quote);
        stream.write(s, 0, s.length);
        stream.write(__Quote);
        stream.write(__Semicolon);
    }

    private static int writeArray(ByteArrayOutputStream stream, Object a, Map<Object, Object> ht, int hv, String charset, int reader) {
        int len = Array.getLength(a);
        byte[] alen = getBytes(new Integer(len));

        stream.write(__a);
        stream.write(__Colon);
        stream.write(alen, 0, alen.length);
        stream.write(__Colon);
        stream.write(__LeftB);
        for (int i = 0; i < len; i++) {
            writeInteger(stream, getBytes(new Integer(i)));
            hv = serialize(stream, Array.get(a, i), ht, hv, charset, reader);
        }
        stream.write(__RightB);
        return hv;
    }

    private static int writeList(ByteArrayOutputStream stream, List<Object> a, Map<Object, Object> ht, int hv, String charset, int reader) {
        int len = a.size();
        byte[] alen = getBytes(new Integer(len));

        stream.write(__a);
        stream.write(__Colon);
        stream.write(alen, 0, alen.length);
        stream.write(__Colon);
        stream.write(__LeftB);
        for (int i = 0; i < len; i++) {
            writeInteger(stream, getBytes(new Integer(i)));
            hv = serialize(stream, a.get(i), ht, hv, charset, reader);
        }
        stream.write(__RightB);
        return hv;
    }
    
    private static int writeIterator(ByteArrayOutputStream stream, Iterator<Object> a, Map<Object, Object> ht, int hv, String charset, int reader){
    	List<Object> list = new ArrayList<Object>();
    	while(a.hasNext()){
    		list.add(a.next());
    	}
    	return writeList(stream, list, ht, hv, charset, reader);
    }

    private static int writeMap(ByteArrayOutputStream stream, Map<Object, Object> h, Map<Object, Object> ht, int hv, String charset, int reader) {
        int len = h.size();
        byte[] hlen = getBytes(new Integer(len));

        if(READER_JS == reader || READER_FLASH == reader)
        	stream.write(__m);
        else
        	stream.write(__a);
        stream.write(__Colon);
        stream.write(hlen, 0, hlen.length);
        stream.write(__Colon);
        stream.write(__LeftB);
        for (Iterator<Object> keys = h.keySet().iterator(); keys.hasNext();) {
            Object key = keys.next();
            if ((key instanceof Byte) || (key instanceof Short)
                    || (key instanceof Integer)) {
                writeInteger(stream, getBytes(key));
            } else if (key instanceof Boolean) {
                writeInteger(stream, new byte[] { ((Boolean) key).booleanValue() ? __1 : __0 });
            } else {
            	int length = -1;
            	if(READER_JS == reader || READER_FLASH == reader)
            		length = String.valueOf(key).length();
                writeString(stream, getBytes(key, charset), length);
            }
            hv = serialize(stream, h.get(key), ht, hv, charset, reader);
        }
        stream.write(__RightB);
        return hv;
    }

    private static int writeObject(ByteArrayOutputStream stream, Object obj, Map<Object, Object> ht, int hv, String charset, int reader) {    	
    	if(obj instanceof PHPSerializable){
    		Map<String,Object> map = SerializeObjectHandle.toMap(obj);
    		LinkedHashMap<Object, Object> wm = new LinkedHashMap<Object, Object>(map.size()+1);
    		wm.put(PHPSerializableClassName, obj.getClass().getName());
    		for(String key : map.keySet()){
    			wm.put(key, map.get(key));
    		}
    		return writeMap(stream, wm, ht, hv, charset, reader);
    	}
    	else{
    		writeNull(stream);
    		
    	}
        return hv;
    }

    private static byte[] getBytes(Object obj) {
        try {
            return obj.toString().getBytes("US-ASCII");
        } catch (Exception e) {
            return obj.toString().getBytes();
        }
    }

    private static byte[] getBytes(Object obj, String charset) {
        try {
            return obj.toString().getBytes(charset);
        } catch (Exception e) {
        	if(obj == null){
        		System.out.println("...here");
        	}
            return obj.toString().getBytes();
        }
    }

    private static String getString(byte[] data, String charset) {
        try {
            return new String(data, charset);
        } catch (Exception e) {
            return new String(data);
        }
    }

    private static Class<?> getClass(String className) {
        try {
            Class<?> cls = Class.forName(className);

            return cls;
        } catch (Exception e) {}
        for (int i = 0; i < __packages.length; i++) {
            try {
                Class<?> cls = Class.forName(
                        __packages[i].getName() + "." + className);

                return cls;
            } catch (Exception e) {}
        }
        return null;
    }

    public static Object newInstance(Class<?> cls) {
        try {
            Constructor<?> ctor = cls.getConstructor(new Class[0]);
            int mod = ctor.getModifiers();

            if (Modifier.isPublic(mod)) {
                return ctor.newInstance(new Object[0]);
            }
        } catch (Exception e) {}
        try {
            Constructor<?> ctor = cls.getConstructor(new Class[] { Integer.TYPE });
            int mod = ctor.getModifiers();

            if (Modifier.isPublic(mod)) {
                return ctor.newInstance(new Object[] { new Integer(0) });
            }
        } catch (Exception e) {}
        try {
            Constructor<?> ctor = cls.getConstructor(new Class[] { Boolean.TYPE });
            int mod = ctor.getModifiers();

            if (Modifier.isPublic(mod)) {
                return ctor.newInstance(new Object[] { new Boolean(false) });
            }
        } catch (Exception e) {}
        try {
            Constructor<?> ctor = cls.getConstructor(new Class[] { String.class });
            int mod = ctor.getModifiers();

            if (Modifier.isPublic(mod)) {
                return ctor.newInstance(new Object[] { "" });
            }
        } catch (Exception e) {}
        Field[] f = cls.getFields();

        for (int i = 0; i < f.length; i++) {
            if (f[i].getType() == cls && Modifier.isStatic(f[i].getModifiers())) {
                try {
                    return f[i].get(null);
                } catch (Exception e) {}
            }
        }
        Method[] m = cls.getMethods();

        for (int i = 0; i < m.length; i++) {
            if (m[i].getReturnType() == cls
                    && Modifier.isStatic(m[i].getModifiers())) {
                try {
                    return m[i].invoke(null, new Object[0]);
                } catch (Exception e) {}
                try {
                    return m[i].invoke(null, new Object[] { new Integer(0) });
                } catch (Exception e) {}
                try {
                    return m[i].invoke(null, new Object[] { new Boolean(false) });
                } catch (Exception e) {}
                try {
                    return m[i].invoke(null, new Object[] { "" });
                } catch (Exception e) {}
            }
        }
        return null;
    }

    public static Number cast(Number n, Class<?> destClass) {
        if (destClass == Byte.class) {
            return new Byte(n.byteValue());
        }
        if (destClass == Short.class) {
            return new Short(n.shortValue());
        }
        if (destClass == Integer.class) {
            return new Integer(n.intValue());
        }
        if (destClass == Long.class) {
            return new Long(n.longValue());
        }
        if (destClass == Float.class) {
            return new Float(n.floatValue());
        }
        if (destClass == Double.class) {
            return new Double(n.doubleValue());
        }
        return n;
    }
    
    private static boolean classMatch(Class<?> source, Class<?> target){
    	Class<?> clazz = source;
    	while(clazz != Object.class){
    		if(clazz == target)
    			return true;
    		clazz = clazz.getSuperclass();
    	}
    	return false;
    }

    @SuppressWarnings("unchecked")
	public static Object cast(Object obj, Class<?> destClass) {
        if (obj == null || destClass == null) {
            return obj;
        } else if (obj.getClass() == destClass) {
            return obj;
        } else if (obj instanceof Number) {
            return cast((Number) obj, destClass);
        } else if ((obj instanceof String) && destClass == Character.class) {
            return new Character(((String)obj).charAt(0));
        } else if ((obj instanceof List) && destClass.isArray()) {
            return toArray((List<Object>) obj, destClass.getComponentType());
        } else if ((obj instanceof List) && classMatch(destClass, Map.class)) {        	
            return toHashMap((List<Object>) obj);
        } else {
            return obj;
        }
    }

    private static HashMap<Object, Object> toHashMap(List<Object> a) {
        int n = a.size();
        HashMap<Object, Object> h = new HashMap<Object, Object>(n);
        for (int i = 0; i < n; i++) {
            h.put(new Integer(i), a.get(i));
        }
        return h;
    }

    private static Object toArray(List<Object> obj, Class<?> componentType) {
        int n = obj.size();
        Object a = Array.newInstance(componentType, n);
        for (int i = 0; i < n; i++) {
            Array.set(a, i, cast(obj.get(i), componentType));
        }
        return a;
    }

    private static int getPos(ByteArrayInputStream stream) {
        try {
            Field pos = stream.getClass().getDeclaredField("pos");
            pos.setAccessible(true);
            return pos.getInt(stream);
        } catch (Exception e) {
            return 0;
        }
    }

    private static void setPos(ByteArrayInputStream stream, int p) {
        try {
            Field pos = stream.getClass().getDeclaredField("pos");
            pos.setAccessible(true);
            pos.setInt(stream, p);
        } catch (Exception e) {}
    }

    public static Object unserialize(byte[] ss) throws IllegalAccessException {
        return unserialize(ss, null, "UTF-8");
    }

    public static Object unserialize(byte[] ss, String charset) throws IllegalAccessException {
        return unserialize(ss, null, charset);
    }

    public static Object unserialize(byte[] ss, Class<?> cls) throws IllegalAccessException {
        return unserialize(ss, cls, "UTF-8");
    }

    public static Object unserialize(byte[] ss, Class<?> cls, String charset) throws IllegalAccessException {
        int hv = 1;
        ByteArrayInputStream stream = new ByteArrayInputStream(ss);
        Object result = unserialize(stream, new HashMap<Object, Object>(), hv, new HashMap<Object, Object>(), charset).value;
        try {
            stream.close();
        } catch (Exception e) {}
        return cast(result, cls);
    }

    private static UnSerializeResult unserialize(ByteArrayInputStream stream, Map<Object, Object> ht, int hv, Map<Object, Object> rt, String charset) throws IllegalAccessException {
        Object obj;
        switch (stream.read()) {
        case __N:
            obj = readNull(stream);
            ht.put(new Integer(hv++), obj);
            return new UnSerializeResult(obj, hv);

        case __b:
            obj = readBoolean(stream);
            ht.put(new Integer(hv++), obj);
            return new UnSerializeResult(obj, hv);

        case __i:
            obj = readInteger(stream);
            ht.put(new Integer(hv++), obj);
            return new UnSerializeResult(obj, hv);

        case __d:
            obj = readDouble(stream);
            ht.put(new Integer(hv++), obj);
            return new UnSerializeResult(obj, hv);

        case __s:
            obj = readString(stream, charset);
            ht.put(new Integer(hv++), obj);
            return new UnSerializeResult(obj, hv);

        case __U:
            obj = readUnicodeString(stream);
            ht.put(new Integer(hv++), obj);
            return new UnSerializeResult(obj, hv);

        case __r:
            return readRef(stream, ht, hv, rt);

        case __a:
            return readArray(stream, ht, hv, rt, charset);

        case __O:
            return readObject(stream, ht, hv, rt, charset);

        case __C:
            return readCustomObject(stream, ht, hv, charset);

        case __R:
            return readPointRef(stream, ht, hv, rt);

        default:
            return null;
        }
    }

    private static String readNumber(ByteArrayInputStream stream) {
        StringBuffer sb = new StringBuffer();
        int i = stream.read();

        while ((i != __Semicolon) && (i != __Colon)) {
            sb.append((char) i);
            i = stream.read();
        }
        return sb.toString();
    }

    private static Object readNull(ByteArrayInputStream stream) {
        stream.skip(1);
        return null;
    }

    private static Boolean readBoolean(ByteArrayInputStream stream) {
        stream.skip(1);
        Boolean b = new Boolean(stream.read() == __1);

        stream.skip(1);
        return b;
    }

    private static Number readInteger(ByteArrayInputStream stream) {
        stream.skip(1);
        String i = readNumber(stream);

        try {
            return new Integer(i);
        } catch (Exception e1) {
        	return new Long(i);
        }
    }

    private static Number readDouble(ByteArrayInputStream stream) {
        stream.skip(1);
        String d = readNumber(stream);

        if (d.equals(__NAN)) {
            return new Double(Double.NaN);
        }
        if (d.equals(__INF)) {
            return new Double(Double.POSITIVE_INFINITY);
        }
        if (d.equals(__NINF)) {
            return new Double(Double.NEGATIVE_INFINITY);
        }
        try {
            return new Long(d);
        } catch (Exception e1) {
            try {
                Float f = new Float(d);

                if (f.isInfinite()) {
                    return new Double(d);
                } else {
                    return f;
                }
            } catch (Exception e2) {
                return new Float(0);
            }
        }
    }

    private static String readString(ByteArrayInputStream stream, String charset) {
        stream.skip(1);
        int len = Integer.parseInt(readNumber(stream));

        stream.skip(1);
        byte[] buf = new byte[len];

        stream.read(buf, 0, len);
        String s = getString(buf, charset);

        stream.skip(2);
        return s;
    }

    private static String readUnicodeString(ByteArrayInputStream stream) {
        stream.skip(1);
        int l = Integer.parseInt(readNumber(stream));

        stream.skip(1);
        StringBuffer sb = new StringBuffer(l);
        int c;

        for (int i = 0; i < l; i++) {
            if ((c = stream.read()) == __Slash) {
                char c1 = (char) stream.read();
                char c2 = (char) stream.read();
                char c3 = (char) stream.read();
                char c4 = (char) stream.read();

                sb.append(
                        (char) (Integer.parseInt(
                                new String(new char[] { c1, c2, c3, c4 }), 16)));
            } else {
                sb.append((char) c);
            }
        }
        stream.skip(2);
        return sb.toString();
    }

    private static UnSerializeResult readRef(ByteArrayInputStream stream, Map<Object, Object> ht, int hv, Map<Object, Object> rt) {
        stream.skip(1);
        Integer r = new Integer(readNumber(stream));

        if (rt.containsKey(r)) {
            rt.put(r, new Boolean(true));
        }
        Object obj = ht.get(r);

        ht.put(new Integer(hv++), obj);
        return new UnSerializeResult(obj, hv);
    }

    private static UnSerializeResult readPointRef(ByteArrayInputStream stream, Map<Object, Object> ht, int hv, Map<Object, Object> rt) {
        stream.skip(1);
        Integer r = new Integer(readNumber(stream));

        if (rt.containsKey(r)) {
            rt.put(r, new Boolean(true));
        }
        Object obj = ht.get(r);

        return new UnSerializeResult(obj, hv);
    }

    private static UnSerializeResult readArray(ByteArrayInputStream stream, Map<Object, Object> ht, int hv, Map<Object, Object> rt, String charset) throws IllegalAccessException {
        stream.skip(1);
        int n = Integer.parseInt(readNumber(stream));

        stream.skip(1);
        Map<Object, Object> h = new HashMap<Object, Object>(n);
        List<Object> al = new ArrayList<Object>(n);
        Integer r = new Integer(hv);

        rt.put(r, new Boolean(false));
        int p = getPos(stream);

        ht.put(new Integer(hv++), h);
        for (int i = 0; i < n; i++) {
            Object key;

            switch (stream.read()) {
            case __i:
                key = cast(readInteger(stream), Integer.class);
                break;

            case __s:
                key = readString(stream, charset);
                break;

            case __U:
                key = readUnicodeString(stream);
                break;

            default:
                return null;
            }
            UnSerializeResult result = unserialize(stream, ht, hv, rt, charset);

            hv = result.hv;
            if (al != null) {
                if ((key instanceof Integer) && (((Integer) key).intValue() == i)) {
                    al.add(result.value);
                } else {
                    al = null;
                }
            }
            h.put(key, result.value);
        }
        if (al != null) {
            ht.put(r, al);
            if (((Boolean) (rt.get(r))).booleanValue()) {
                hv = r.intValue() + 1;
                setPos(stream, p);
                for (int i = 0; i < n; i++) {
                    int key;

                    switch (stream.read()) {
                    case __i:
                        key = ((Integer) cast(readInteger(stream), Integer.class)).intValue();
                        break;

                    default:
                        return null;
                    }
                    UnSerializeResult result = unserialize(stream, ht, hv, rt,
                            charset);

                    hv = result.hv;
                    al.set(key, result.value);
                }
            }
        }
        rt.remove(r);
        stream.skip(1);
        return new UnSerializeResult(ht.get(r), hv);
    }

	private static UnSerializeResult readObject(ByteArrayInputStream stream, Map<Object, Object> ht, int hv, Map<Object, Object> rt, String charset) throws IllegalAccessException {
        stream.skip(1);
        int len = Integer.parseInt(readNumber(stream));

        stream.skip(1);
        byte[] buf = new byte[len];

        stream.read(buf, 0, len);
//        String cn = getString(buf, charset);

        stream.skip(2);
        int n = Integer.parseInt(readNumber(stream));

        stream.skip(1);
//        Class<?> cls = getClass(cn);
        Object o;

//        if (cls != null) {
//            if ((o = newInstance(cls)) == null) {
//                o = new HashMap<Object, Object>(n);
//            }
//        } else {
        Map<Object, Object> map = new HashMap<Object, Object>(n);
//        }
        ht.put(new Integer(hv++), map);
        for (int i = 0; i < n; i++) {
            String key;

            switch (stream.read()) {
            case __s:
                key = readString(stream, charset);
                break;

            case __U:
                key = readUnicodeString(stream);
                break;

            default:
                return null;
            }
            if (key.charAt(0) == (char) 0) {
                key = key.substring(key.indexOf("\0", 1) + 1);
            }
            UnSerializeResult result = unserialize(stream, ht, hv, rt, charset);

            hv = result.hv;
            map.put(key, result.value);
        }
        o = map;
        if(map.containsKey(PHPSerializableClassName)){
        	String className = (String)map.get(PHPSerializableClassName);
        	try {
				Class<?> clazz = Class.forName(className);
				if(clazz != null){
					Map<String, Object> sm = new HashMap<String, Object>();
					for(Object mkey : map.keySet()){
						if(mkey instanceof String){
							String skey = (String) mkey;
							if(skey == PHPSerializableClassName)
								continue;
							sm.put(skey, map.get(mkey));
						}
					}
					o = SerializeObjectHandle.toBean(clazz, sm);
				}
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
        }
        stream.skip(1);
        Method __wakeup = null;

        try {
            __wakeup = o.getClass().getMethod("__wakeup", new Class[0]);
            __wakeup.invoke(o, new Object[0]);
        } catch (Exception e) {}
        return new UnSerializeResult(o, hv);
    }

    private static UnSerializeResult readCustomObject(ByteArrayInputStream stream, Map<Object, Object> ht, int hv, String charset) {
        stream.skip(1);
        int len = Integer.parseInt(readNumber(stream));

        stream.skip(1);
        byte[] buf = new byte[len];

        stream.read(buf, 0, len);
        String cn = getString(buf, charset);

        stream.skip(2);
        int n = Integer.parseInt(readNumber(stream));

        stream.skip(1);
        Class<?> cls = getClass(cn);
        Object o;

        if (cls != null) {
            o = newInstance(cls);
        } else {
            o = null;
        }
        ht.put(new Integer(hv++), o);
        if (o == null) {
            stream.skip(n);
        } else {
            stream.skip(n);
        }
        stream.skip(1);
        return new UnSerializeResult(o, hv);
    }
    
    public static void main(String[] args){
    	try{
//    		Map<String, String> map = new HashMap<String, String>();
//    		map.put("id", "中文");
//    		byte[] bts = PHPSerializer.serialize(map);
//    		System.out.println(new String(bts));
//    		Map<String, String> map = new HashMap<String, String>();
//    		map.put("content", "<p>地夺地</p>");
//    		System.out.println(new String(PHPSerializer.serialize(map)));
    		String str = "a:3:{s:5:\"dirId\";i:20;s:4:\"pics\";a:1:{i:0;a:9:{s:6:\"custId\";s:5:\"phfzc\";s:7:\"ownerId\";s:1:\"0\";s:8:\"folderId\";s:1:\"1\";s:6:\"picKey\";s:16:\"50f865ca5f1d0505\";s:7:\"picName\";s:6:\"Tulips\";s:6:\"picExt\";s:3:\"jpg\";s:7:\"picSize\";i:86032;s:8:\"picWidth\";i:1024;s:9:\"picHeight\";i:768;}}s:6:\"custId\";s:5:\"phfzc\";}";
    		Object obj = PHPSerializer.unserialize(str.getBytes());
    		System.out.println(obj);
    	}
    	catch(Exception e){
    		e.printStackTrace();
    	}
    }
    
	public static boolean isPHPSerializable(Class<?> clazz){
		if(clazz.isInterface()){
			return clazz == PHPSerializable.class;
		}
		Class<?>[] clzs = clazz.getInterfaces();
		if(clzs == null || clzs.length == 0)
			return false;
		for(int i = 0; i < clzs.length; i++){
			Class<?> clz = clzs[i];
			if(clz == PHPSerializable.class){
				return true;
			}
		}
		return false;
	}
}